package com.ilaber.beehive;

import java.awt.Frame;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.font.ImageGraphicAttribute;
import java.io.IOException;
import java.net.URISyntaxException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

import javax.swing.JFrame;
import javax.swing.JLabel;

import org.apache.commons.math3.stat.StatUtils;
import org.apache.commons.math3.stat.descriptive.moment.StandardDeviation;
import org.opencv.core.Core;
import org.opencv.core.CvType;
import org.opencv.core.Mat;
import org.opencv.core.MatOfPoint;
//import org.opencv.core.MatOfPoint2f;
import org.opencv.core.Point;
import org.opencv.core.Scalar;
import org.opencv.core.Size;
import org.opencv.highgui.HighGui;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;
import org.opencv.imgproc.Moments;

public class BeehiveFrame {
	static {
		System.load(BeehiveFrame.class.getResource("/dll/opencv_java455.dll").getFile());
	}
	public static void main(String[] args) throws IOException, URISyntaxException {
//		System.out.println(Beehive.class.getClassLoader().getResource("imags/beehive-1.jpg").getFile());
		String path = Paths.get(BeehiveFrame.class.getClassLoader().getResource("imags/beehive-1.jpg").toURI()).toString();
		String target = Files.createTempFile("target_"+ System.currentTimeMillis(), "jpg").toString();
		copyFile(path, target);
//		Beehive.class.getClassLoader().getResource("images/beehive-1.jpg").getPath();
		Mat mat = Imgcodecs.imread(target);
		
		Mat targetHsv = new Mat();
		Imgproc.cvtColor(mat, targetHsv, Imgproc.COLOR_BGR2HSV);
		
		HighGui.namedWindow("图像HSV模式获取");
		
		HighGui.imshow("图像HSV模式获取", targetHsv);
		
		HighGui.waitKey();
//		JFrame frame = HighGui.windows.get("图像HSV模式获取").frame;
		JLabel lbl = HighGui.windows.get("图像HSV模式获取").lbl;
		if (lbl != null) {
//			frame.add
			lbl.addMouseListener(new MouseAdapter() {
				public void mouseClicked(MouseEvent e) {
					System.out.println("鼠标点击事件，按下，释放 X:"+e.getX() + "Y:" + e.getY());
					System.out.println(Arrays.toString(targetHsv.get(e.getY(),e.getX() )));
				}
			});
		}
	}
	
	private static Mat detectHSColor(Mat image,Scalar lower,Scalar upper) {
//		Mat mat = new Mat(image.rows(),image.cols(),image.type());
		Mat target = new Mat();
		Imgproc.cvtColor(image, target, Imgproc.COLOR_BGR2HSV);
		HighGui.imshow("hsvImage", target);
		Mat mask1 = new Mat();
		Core.inRange(target, lower, upper, mask1);
		return mask1;
	}
	
	private static void open(Mat src,Mat dst) {
		Mat kernel = Imgproc.getStructuringElement(Imgproc.MORPH_RECT, new Size(3, 3), new Point(-1, -1));
		Imgproc.morphologyEx(src, dst, Imgproc.MORPH_OPEN, kernel);
	}
	
	private static double calcArea(Mat mask,Mat originMat,boolean isOpen) {
		Mat dst = new Mat();

		if (isOpen) {
			open(mask, dst);
		} else {
			dst = mask;
		}
		
		
		List<MatOfPoint> contours = new ArrayList<MatOfPoint>();
	    Mat hierarchy = new Mat();
	    Imgproc.findContours(dst, contours, hierarchy, Imgproc.RETR_TREE,
	                Imgproc.CHAIN_APPROX_TC89_KCOS, new Point(-1, -1));
	    
	   
	    //相当于创建和原图尺寸相同一张黑色的图，用于后面画线作图
        Mat contoursImg = Mat.zeros(originMat.size(), CvType.CV_8UC3);
        double totalArea = 0.0;
        for(int i=0;i<contours.size();i++){
            double area = Imgproc.contourArea(contours.get(i));
//            Imgc
//            Point center = new Point();
//            MatOfPoint2f matOfPoint2f = new MatOfPoint2f();
//            contours.get(i).convertTo(matOfPoint2f, CvType.CV_32F);
//
//            Imgproc.minEnclosingCircle(matOfPoint2f, center, new float[1]);
//            System.out.println("中心:"+ center.x);
//            System.out.println("中心:"+ center.y);
            Moments moments = Imgproc.moments(contours.get(i));
            // 计算中心
            double cx = moments.m10/moments.m00;
            double cy = moments.m01/moments.m00;
//            System.out.println("中心1:"+ cx);
//            System.out.println("中心2:"+ cy);
            
            double[] pointSignle = mask.get((int)cx, (int)cy);
            
            if (pointSignle != null && pointSignle[0] == 255) {//单通道 只统计白色面积 单位像素
            	totalArea += area;
//            	Imgproc.circle(contoursImg, new Point(cx, cy), 1,  new Scalar(0,0,255));
            	Imgproc.drawContours(contoursImg,contours,i, new Scalar(0,255,255),
                        1,1,hierarchy,0,new Point(0, 0));
            }
        }
        HighGui.imshow("mask", mask);
        HighGui.imshow("描绘", contoursImg);
        System.out.println("计算出来的蜂巢子的面积是：" + totalArea);
		
		Mat out = new Mat();
		
		originMat.copyTo(out,dst);
		
		HighGui.imshow("运行以后图", out);
		
		return totalArea;
	}
	
	private static double calcSigleArea(Mat mask,Mat originMat,double minArea) {
		Mat dst =  new Mat();
//		HighGui.imshow("模板", mask);
		Core.bitwise_not(mask, dst);
//		HighGui.imshow("运行以后图", mask);
		Mat out = new Mat();
		originMat.copyTo(out,dst);
		
//		HighGui.imshow("反向", out);
		Imgproc.cvtColor(out, out, Imgproc.COLOR_RGB2GRAY);
		Imgproc.threshold(out, out, 0, 255, Imgproc.THRESH_BINARY | Imgproc.THRESH_OTSU);//灰度图像二值化
		Imgproc.GaussianBlur(out, out, new Size(1,1), 0);
//		Imgproc.Canny(out, out, 10, 10);
//		HighGui.imshow("高斯模糊", out);
		
		List<MatOfPoint> contours = new ArrayList<MatOfPoint>();
	    Mat hierarchy = new Mat();
	    
	    int startTimes = 1;
	    
	    Imgproc.findContours(out, contours, hierarchy, Imgproc.RETR_TREE,
	                Imgproc.CHAIN_APPROX_TC89_KCOS, new Point(-1, -1));
	    
	    List<MatOfPoint> validContours = contours.stream().filter(coutoure->{
	    	  Moments moments = Imgproc.moments(coutoure);
	            // 计算中心
	            double cx = moments.m10/moments.m00;
	            double cy = moments.m01/moments.m00;
	            double[] pointSignle = dst.get((int)cy, (int)cx);
	            if (pointSignle != null && pointSignle[0] == 255) {
	            	return true;
	            }
	            return false;
	    }).collect(Collectors.toList());
	    
	    List<Double> areaList = validContours.stream().map(coutoure->Imgproc.contourArea(coutoure)).collect(Collectors.toList());
//	    
	    judgeDatas(areaList,minArea,true,startTimes);
//	    
	    double[] areaArray = areaList.stream().mapToDouble(data->data).toArray();
	    double standardDeviation = new StandardDeviation().evaluate(areaArray);
	    double mean = StatUtils.mean(areaArray);
	    //相当于创建和原图尺寸相同一张黑色的图，用于后面画线作图
        Mat contoursImg = Mat.zeros(originMat.size(), CvType.CV_8UC3);
        validContours.forEach(coutoure->{
        	int i = contours.indexOf(coutoure);
        	double area = Imgproc.contourArea(coutoure);
        	if (area > minArea && Math.abs( area - mean) < 3*standardDeviation ) {
        		Imgproc.drawContours(contoursImg,contours,i, new Scalar(0,255,255),
                        1,1,hierarchy,0,new Point(0, 0));
        	} 
        });
        HighGui.imshow("运行以后图", contoursImg);
		return mean;
	}
	
	private static void judgeDatas(List<Double> list,double minArea,boolean lastSkiped,int times) {
			double[] areaArray = list.stream().mapToDouble(data->data).toArray();
			double standardDeviation = new StandardDeviation().evaluate(areaArray);
			double mean = StatUtils.mean(areaArray);
		    if (!lastSkiped || times > 10) {
		    	return ;
		    } 
	        boolean skip = false;
	        for (double a : areaArray) {
	        	if (a <= minArea || Math.abs( a - mean) > 3*standardDeviation) {
	        		skip = true;
	        		list.remove(a);
	        	}
	        }
	        judgeDatas(list, minArea, skip, times+1);
	}
	
	private static synchronized void copyFile(String path,String target) throws IOException {
		Path sourcePath = Paths.get(path);
		Path desPath = Paths.get(target);
		Files.copy(sourcePath,desPath,StandardCopyOption.REPLACE_EXISTING);
	}

}
